package funcSless

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"time"

	"gitee.com/wchpub/fnsvr"
	"go.mongodb.org/mongo-driver/bson"
)

//封装一些对脏数据的操作接口

// 块脏数据哈希表的key
const REDIS_BLOCK_DIRTY_KEY = "funcsless:block_dirty_map"

// 生成块数据的redis key
func makeBlockRedisKey(playerId, blockName string) string {
	return fmt.Sprintf("gamedata:%s:%s", blockName, playerId)
}

// 生成块数据的mongo集合名
func makeBlockMongoCollection(blockName string) string {
	return fmt.Sprintf("gamedata_%s", blockName)
}

// 生成脏数据哈希表中的key
func makeBlockDirtyFieldName(playerId, blockName string) string {
	return blockName + "_" + playerId
}

func splitByLastUnderscore(s string) (string, string) {
	lastIndex := strings.LastIndex(s, "_")
	if lastIndex == -1 {
		return s, ""
	}
	return s[:lastIndex], s[lastIndex+1:]
}

// 脏数据同步协程
func dataSyncCo() {
	//从数据库读取脏标记

	rdb := gFuncSlessEnv.Redis
	ctx := context.Background()

	result, err := rdb.HGetAll(ctx, REDIS_BLOCK_DIRTY_KEY).Result()
	if err != nil {
		fnsvr.Log().Error("DataSyncCo Redis HGetAll", "err", err)
		return
	}

	increaseKeyValue := make(map[string]int64)

	// 遍历输出所有字段和值
	for field, value := range result {
		blockname, playerid := splitByLastUnderscore(field)

		//从redis读取档案
		blockData, err := rdb.HGetAll(ctx, makeBlockRedisKey(playerid, blockname)).Result()
		if err != nil {
			fnsvr.Log().Error("DataSyncCo read blockData", "field", field, "err", err)
			continue
		}

		//必要数据为空，是数据刚过期的时候写入了增量变更导致，因此应该同步到数据库
		//版本号信息为空，判定为无效档案
		//_, verok := blockData[GAME_DATA_VER_KEY]
		//if !verok {
		//	fnsvr.Log().Error("DataSyncCo read blockData#2", "field", field, "err", err)
		//	continue
		//}

		if len(blockData) > 0 {
			//数据写入mongo数据库

			mongoPlyid, err := fnsvr.GenerateMongoDbId(playerid)
			if err != nil {
				fnsvr.Log().Error("DataSyncCo GeneratePlayerDbId", "playerid", playerid, "objId", mongoPlyid.Hex(), "err", err)
				continue
			}

			// 生成更新数据
			bsonUpdates := bson.D{}
			for kk, vv := range blockData {
				bsonUpdates = append(bsonUpdates, bson.E{Key: kk, Value: vv})
			}
			updateData := bson.M{
				"$set": bsonUpdates, // 使用bson.M无需字段顺序
			}

			_, err = gFuncSlessEnv.Mongo.UpdateOne(
				makeBlockMongoCollection(blockname),
				"_id",
				mongoPlyid,
				updateData,
			)
			if err != nil {
				//mongo.ErrNoDocuments

				fnsvr.Log().Error("DataSyncCo save to mongo", "playerid", playerid, "blockname", blockname, "err", err)
				continue
			}

			fnsvr.Log().Info("save", "playerid", playerid, "blockname", blockname)
		}

		//清脏标记
		{
			newStrV := value
			if !strings.HasPrefix(newStrV, "-") {
				newStrV = "-" + newStrV
			}
			num, err := strconv.ParseInt(newStrV, 10, 64)
			if err != nil {
				fnsvr.Log().Error("DataSyncCo parseInt", "playerid", playerid, "blockname", blockname, "err", err)
				continue
			}
			increaseKeyValue[field] = num
		}

		//延迟1毫秒
		time.Sleep(1 * time.Millisecond)
	}

	if len(increaseKeyValue) > 0 {
		_, err = fnsvr.BatchAtomicIncreaseHashFields(rdb, REDIS_BLOCK_DIRTY_KEY, increaseKeyValue)
		if err != nil {
			fnsvr.Log().Error("DataSyncCo BatchAtomicIncreaseHashFields", "err", err)
		}
	}

}
